Xcode15之前的处理方案
在SwiftUI中,特点之一就是能支持实时预览页面UI效果,从而提高开发效率。而使用UIKit开发的过程中,尽管可以好用Xib/Storyborad/@IBDesignable等看到开发效果,但是开发体验不好。
我们知道,如果想在SwiftUI中嵌入UIKit的页面,需要实现UIViewRepresentable
协议。因此实现了该协议,基本就能实现实时预览UIKit的效果,我们需要做的只是做一些简单的封装,简化使用。
预览UIView
swift
import SwiftUI
struct UIViewPreview<View: UIView>: UIViewRepresentable {
let view: View
init(_ builder: @escaping () -> View) {
view = builder()
}
// MARK: UIViewRepresentable
func makeUIView(context: Context) -> UIView {
return view
}
func updateUIView(_ view: UIView, context: Context) {
view.setContentHuggingPriority(.defaultHigh, for: .horizontal)
view.setContentHuggingPriority(.defaultHigh, for: .vertical)
}
}
struct UIView_Previews: PreviewProvider {
static var previews: some View {
UIViewPreview {
let vc = UIView()
vc.backgroundColor = .green
return vc
}
}
}
import SwiftUI
struct UIViewPreview<View: UIView>: UIViewRepresentable {
let view: View
init(_ builder: @escaping () -> View) {
view = builder()
}
// MARK: UIViewRepresentable
func makeUIView(context: Context) -> UIView {
return view
}
func updateUIView(_ view: UIView, context: Context) {
view.setContentHuggingPriority(.defaultHigh, for: .horizontal)
view.setContentHuggingPriority(.defaultHigh, for: .vertical)
}
}
struct UIView_Previews: PreviewProvider {
static var previews: some View {
UIViewPreview {
let vc = UIView()
vc.backgroundColor = .green
return vc
}
}
}
预览Controller
swift
import SwiftUI
struct UIViewControllerPreview<ViewController: UIViewController>: UIViewControllerRepresentable {
func updateUIViewController(_ uiViewController: ViewController, context: Context) {
}
let viewController: ViewController
init(_ builder: @escaping () -> ViewController) {
viewController = builder()
}
// MARK: - UIViewControllerRepresentable
func makeUIViewController(context: Context) -> ViewController {
viewController
}
}
struct ControllerPreviews_Previews: PreviewProvider {
static var previews: some View {
UIViewControllerPreview {
LoginViewController()
}
}
}
import SwiftUI
struct UIViewControllerPreview<ViewController: UIViewController>: UIViewControllerRepresentable {
func updateUIViewController(_ uiViewController: ViewController, context: Context) {
}
let viewController: ViewController
init(_ builder: @escaping () -> ViewController) {
viewController = builder()
}
// MARK: - UIViewControllerRepresentable
func makeUIViewController(context: Context) -> ViewController {
viewController
}
}
struct ControllerPreviews_Previews: PreviewProvider {
static var previews: some View {
UIViewControllerPreview {
LoginViewController()
}
}
}
报错处理
老项目报错:
c
| RemoteHumanReadableError: 未能完成该操作。Transaction failed. Process failed to launch. (process launch failed)
|
| BSTransactionError (1):
| ==transaction: <FBApplicationProcessLaunchTransaction: 0x600003b0d340>
| ==error-description: Process failed to launch.
| ==precipitating-error: Error Domain=FBProcessExit Code=64 "The process failed to launch." UserInfo={NSLocalizedFailureReason=The process failed to launch., BSErrorCodeDescription=launch-failed, NSUnderlyingError=0x600000c48b10 {Error Domain=RBSRequestErrorDomain Code=5 "Launch failed." UserInfo={NSLocalizedFailureReason=Launch failed., NSUnderlyingError=0x600000c48e70 {Error Domain=NSPOSIXErrorDomain Code=111 "Unknown error: 111" UserInfo={NSLocalizedDescription=Launchd job spawn failed}}}}}
| ==error-reason: process launch failed
| ==NSLocalizedFailureReason: Transaction failed. Process failed to launch. (process launch failed)
| RemoteHumanReadableError: 未能完成该操作。Transaction failed. Process failed to launch. (process launch failed)
|
| BSTransactionError (1):
| ==transaction: <FBApplicationProcessLaunchTransaction: 0x600003b0d340>
| ==error-description: Process failed to launch.
| ==precipitating-error: Error Domain=FBProcessExit Code=64 "The process failed to launch." UserInfo={NSLocalizedFailureReason=The process failed to launch., BSErrorCodeDescription=launch-failed, NSUnderlyingError=0x600000c48b10 {Error Domain=RBSRequestErrorDomain Code=5 "Launch failed." UserInfo={NSLocalizedFailureReason=Launch failed., NSUnderlyingError=0x600000c48e70 {Error Domain=NSPOSIXErrorDomain Code=111 "Unknown error: 111" UserInfo={NSLocalizedDescription=Launchd job spawn failed}}}}}
| ==error-reason: process launch failed
| ==NSLocalizedFailureReason: Transaction failed. Process failed to launch. (process launch failed)
解决方案: 勾选 Show Rosetta Destinations
测试效果: 可能是在老项目上运行的原因,非常卡顿。
Xcode15 宏 #Preview{}
使用宏#Preview{}
可以支持UIKit 和 SwiftUI 。 需要注意如果系统不是支持>=iOS17, 必须增加@available(iOS 17, *)
swift
import SwiftUI
@available(iOS 17, *)
#Preview {
UISwitch()
}
import SwiftUI
@available(iOS 17, *)
#Preview {
UISwitch()
}
通过抽离SwiftUI代码的方式提速
实际问题
用SwiftUI来预览UIView页面,刷新慢,实际体验并不好。